package web

import (
	"context"
	filev1 "gitee.com/xiao_hange/go-admin-api/api/proto/gen/file/v1"
	"gitee.com/xiao_hange/go-admin-pkg/pkg/ginx"
	"gitee.com/xiao_hange/go-admin-pkg/pkg/logger"
	regexp "github.com/dlclark/regexp2"
	"github.com/gin-gonic/gin"
	"go-admin/server/internal/web/form"
	"go-admin/server/internal/web/vo"
	"go-admin/server/utils"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/trace"
	"google.golang.org/grpc/status"
	"io"
	"net/http"
	"strconv"
)

var (
	_              handler = &FileHandler{}
	ErrDataTooMuch         = "数据过多，已邮件的形式发送给您"
	//ErrDataTooMuch         = errors.New("数据过多，已邮件的形式发送给您")
)

type FileHandler struct {
	svc      filev1.FileServiceClient
	emailExp *regexp.Regexp
	l        logger.AppLogger
	tracer   trace.Tracer
}

func NewFileHandler(svc filev1.FileServiceClient, l logger.AppLogger) *FileHandler {
	const (
		emailRegexPattern = "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$"
	)
	emailExp := regexp.MustCompile(emailRegexPattern, regexp.None)
	return &FileHandler{
		svc:      svc,
		emailExp: emailExp,
		l:        l,
		tracer:   otel.GetTracerProvider().Tracer("File web层"),
	}
}

func (f *FileHandler) RegisterRoutes(server *gin.Engine) {
	fg := server.Group("/file")

	fg.POST("/upload", f.upload)
	fg.GET("/lst", f.lst)
	fg.PUT("/edit-name", ginx.WrapBody[form.FileReq](f.editName))
	fg.DELETE("/del-file", ginx.WrapBody[form.FileReq](f.delFile))
	fg.GET("/export", ginx.WrapBody[form.ExportReq](f.export))
}

func (f *FileHandler) lst(ctx *gin.Context) {
	var req form.FileLstReq
	err := ctx.Bind(&req)
	if err != nil {
		return
	}

	Resp, err := f.svc.GetLifeLst(ctx.Request.Context(), &filev1.GetLifeLstRequest{
		Page:  req.Page,
		Limit: req.Limit,
		Types: uint32(req.Type),
	})
	if err != nil {
		s, _ := status.FromError(err)
		RenderJSON(ctx, http.StatusOK, http.StatusOK, "内部错误！"+s.Message(), nil)
		return
	}
	var res []vo.FileVo
	for _, d := range Resp.File {
		res = append(res, vo.FileVo{
			ID:         d.ID,
			Type:       d.Type,
			OldName:    d.OldName,
			NewName:    d.NewName,
			FileType:   d.FileType,
			Image:      d.Image,
			UpdateTime: d.UpdateTime.AsTime().Format("2006-01-02 15:04:05"),
			CreateTime: d.CreateTime.AsTime().Format("2006-01-02 15:04:05"),
		})
	}

	RenderJSONPage(ctx, http.StatusOK, http.StatusOK, "ok！", res, Resp.Nt)
	return
}

func (f *FileHandler) upload(ctx *gin.Context) {
	file, _ := ctx.FormFile("file")
	uploadedFile, _ := file.Open()
	defer uploadedFile.Close()
	fileType := file.Header.Get("Content-Type")
	fileBytes, err := io.ReadAll(uploadedFile)
	doFile, err := f.svc.UploadFile(ctx.Request.Context(), &filev1.UploadFileRequest{
		OldName:  file.Filename,
		FileType: fileType,
		Size:     strconv.FormatInt(file.Size, 10),
		Reader:   fileBytes,
	})
	if err != nil {
		RenderJSON(ctx, http.StatusOK, http.StatusOK, "上传失败！", nil)
	}
	data := vo.FileVO{
		Val: doFile.Val,
		Url: doFile.Url,
	}
	RenderJSON(ctx, http.StatusOK, 200, "ok", data)
}

func (f *FileHandler) editName(ctx *gin.Context, req form.FileReq) ginx.Result {
	var err error
	if err = utils.Verify(req, utils.EditName); err != nil {
		return ginx.Result{Code: http.StatusNoContent, Msg: err.Error()}
	}
	_, err = f.svc.EditName(ctx.Request.Context(), &filev1.EditNameRequest{
		Id:   req.FileId,
		Name: req.Name,
	})
	if err != nil {
		return ginx.Result{Code: http.StatusNoContent, Msg: err.Error()}
	}
	if err != nil {
		return ginx.Result{}
	}
	return ginx.Result{Code: http.StatusOK, Msg: "修改成功！"}
}

func (f *FileHandler) delFile(ctx *gin.Context, req form.FileReq) ginx.Result {
	var err error
	if err = utils.Verify(req, utils.DelFile); err != nil {
		return ginx.Result{Code: http.StatusNoContent, Msg: err.Error()}
	}
	_, err = f.svc.DelFile(ctx.Request.Context(), &filev1.DelFileRequest{
		Id:   req.FileId,
		Name: req.Name,
	})
	if err != nil {
		return ginx.Result{Code: http.StatusNoContent, Msg: err.Error()}
	}
	if err != nil {
		return ginx.Result{}
	}
	return ginx.Result{Code: http.StatusOK, Msg: "修改成功！"}
}

func (f *FileHandler) export(ctx *gin.Context, req form.ExportReq) ginx.Result {
	spanCtx := context.WithValue(ctx.Request.Context(), "Enable", true)
	spanCtx, span = f.tracer.Start(spanCtx, "File web层:export", trace.WithSpanKind(trace.SpanKindClient))
	defer span.End()
	if req.Mail != "" {
		ok, err := f.emailExp.MatchString(req.Mail)
		if err != nil {
			return ginx.Result{Code: http.StatusNoContent, Msg: "内部错误"}
		}
		if !ok {
			return ginx.Result{Code: http.StatusNoContent, Msg: "邮箱格式不正确"}
		}
	}

	//lists, total, err := f.svc.GetExportData(ctx.Request.Context(), int(req.Page), int(req.Limit), req.Export, req.Mail)
	Resp, err := f.svc.GetExportData(spanCtx, &filev1.GetExportDataRequest{
		Page:   req.Page,
		Limit:  req.Limit,
		Export: int64(req.Export),
		Mail:   req.Mail,
	})
	if err != nil {
		s, _ := status.FromError(err)
		if s.Message() == ErrDataTooMuch {
			if req.Mail == "" {
				return ginx.Result{Code: http.StatusNoContent, Msg: "数据过多，需要通过邮箱的方式进行下载，请填写正确的邮箱"}
			}
			return ginx.Result{Code: http.StatusOK, Msg: "数据过多，通过邮件的方式发送给该邮箱[" + req.Mail + "]"}
		}
		return ginx.Result{Code: http.StatusNoContent, Msg: "内部错误," + s.Message()}
	}
	var res []vo.DataVo
	for _, d := range Resp.Data {
		res = append(res, vo.DataVo{
			ID:         d.Id,
			Title:      d.Title,
			Content:    d.Content,
			UpdateTime: d.UpdateTime.AsTime(),
			CreateTime: d.CreateTime.AsTime(),
		})
	}
	return ginx.Result{Code: http.StatusOK, Msg: "Ok", Data: res, Count: int(Resp.Nt)}
}
